package cn.itcast.nems.studentrecord.service.studentrecord;

import cn.itcast.ic.common.bean.Page;
import cn.itcast.ic.common.exception.v2.BizException;
import cn.itcast.nems.common.BasePageRequest;
import cn.itcast.nems.oldems.dto.StudentRecordClazzDTO;
import cn.itcast.nems.order.dao.dataobject.RefundClazzInfosDO;
import cn.itcast.nems.studentrecord.api.StudentRecordApi;
import cn.itcast.nems.studentrecord.constant.ReferenceTypeEnum;
import cn.itcast.nems.studentrecord.dao.dataobject.*;
import cn.itcast.nems.studentrecord.dao.entity.StudentRecord;
import cn.itcast.nems.studentrecord.dto.StudentRecordDTO;
import cn.itcast.nems.studentrecord.dto.StudentRecordJournalVo;
import cn.itcast.nems.studentrecord.dto.StudentRecordWithStudentDTO;
import cn.itcast.nems.studentrecord.dto.studentrecord.StudentRecordMessageDTO;
import cn.itcast.nems.studentrecord.dto.studentrecord.StudentRecordRefundDTO;
import cn.itcast.nems.studentrecord.service.settlement.SettlementCalculator;
import cn.itcast.nems.studentrecord.service.settlement.SettlementResult;
import org.apache.ibatis.annotations.Param;
import org.springframework.lang.NonNull;

import java.time.LocalDate;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * <p>
 * 学籍业务接口
 * </p>
 *
 * @author zhouwei
 * @since 2023/11/6 3:17 PM
 **/
public interface StudentRecordService extends StudentRecordApi {

    /**
     * <p>
     * 学籍为“休学班级”且 对应班级为 【休学】， -- 需要排除休学归来的情况
     * 1、检查“休学班级”的学籍是否存在休学凭单 ，  如果有取该凭单原学籍对应的班级
     * 2、不存在休学凭单 ，  取当前学籍对应班级
     * </p>
     *
     * @param studentRecordId 学籍ID
     * @author zhouwei
     * @since 2024/4/10 11:58 AM
     **/
    StudentRecord suspensionStudentRecord(String studentRecordId);

    /**
     *<p> 1、根据”学籍ID“查询”学生ID“对应的有效学籍列表 ，按照班级类型进行排序（就业班、基础班） ；</p>
     *<p> 2、计算学生ID对应 学生【可退金额】 ，  遍历学籍列表 ， 叠加每个学籍【可退金额】 ， 公式：【可退金额】 =  【学籍已付金额】+ 【学籍转班转入金额】 - 【学籍退费金额】 ；</p>
     *<p> 3、检查是否满足：学生【可退金额】  >=  【退费金额】  ， 如果满足执行下一步， 否则提示 ”退费的金额不能大于已支付金额！”；</p>
     *
     * @param studentRecord 学籍
     * @param amount 退费金额
     * @param state 凭单状态
     */
    void validateAmount(final StudentRecord studentRecord, int amount, String state) ;

    /**
     *  获取已生效的学籍
     * @param studentId 学员ID
     * @return 学籍列表， 为空返回 null
     */
    List<StudentRecordDO> findValidStudentRecordByStudentId(Integer studentId) ;

    /**
     * 查询学籍对应的学员ID
     *
     * @param studentRecordIds 学籍ID
     * @return 学籍和学员ID的map，key：学籍ID，value：学员ID
     */
    Map<String, Integer> findStudentIds(Set<String> studentRecordIds);
    
    /**
     * 
     * 功能描述：获取学籍对应学生ID
     *
     * @param id 学籍ID
     * @return 学生ID
     * 
     * @author 刘曙
     *
     * @since 2024年3月19日
     *
     * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
     */
    Integer getStudentIdByID(String id);

    /**
     * 查询学生ID对应的学籍列表
     * @param studentId 学生ID
     * @param excludeIds 需要过滤的学籍ID
     * @return 学籍列表 ， 为空返回null
     */
    List<StudentRecord> findStudentRecordListByStudentId (Integer studentId , Set<String> excludeIds ) ;

    /**
     * 使学籍无效
     *
     * @param studentRecordId 学籍ID
     */
    void invalidStudentRecord(String studentRecordId);

    /**
     * 查询班级有效学籍数；学籍状态有效(VALID | FINISHED），没有出班或出班日期大于当前日期
     *
     * @param clazzId 班级ID
     * @return 有效学籍数
     */
    int findValidStudentRecordCount(int clazzId);

    /**
     * 增加学籍；仅添加学籍实体，创建学籍的完整逻辑见：StudentRecordCreateService.createStudentRecord
     *
     * @param studentRecord 学籍
     */
    void addStudentRecord(StudentRecord studentRecord);

    /**
     * 查找指定学生在班（未结算、未出班）的学籍（包含还未生效的学籍）
     *
     * @param studentId 学员ID
     * @param clazzId   班级ID
     * @return 学籍，如果不存在为null
     */
    StudentRecord findInClazzStudentRecord(int studentId, int clazzId);

    /**
     * 查找指定学生的学籍（包括无效和已出班的，优先返回有效的）
     *
     * @param studentId 学员ID
     * @param clazzId   班级ID
     * @return 学籍，如果不存在为null
     */
    StudentRecord findStudentRecord(int studentId, int clazzId);

    /**
     * 
     * 功能描述：查找指定班级在班的学籍（含学生基础信息，不含未生效的学籍）
     *
     * @param clazzId 班级ID
     * @return 在班学籍列表
     * 
     * @author 刘曙
     *
     * @since 2024年1月4日
     *
     * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
     */
    List<StudentRecordWithStudentDTO> findInClazzStudentRecord(int clazzId);
    
    /**
     * 查找给定日期的出班（结算日期）的学籍
     *
     * @param outDate 出班（结算）日期
     * @return 学籍
     */
    List<StudentRecordMessageDTO> findOutStudentRecords(LocalDate outDate);

    /**
     * 修改学籍
     *
     * @param update 非空字段都将被更新，id字段必须有
     */
    void updateStudentRecordById(StudentRecord update);

    /**
     * 批量更新学籍
     *
     * @param updateCmds 更新对象，id必须提供
     */
    void batchUpdateById(List<StudentRecord> updateCmds);

    /**
     * 根据ID查询学籍
     *
     * @param id 学籍ID
     * @return 学籍
     */
    StudentRecord getById(String id);
    StudentRecord getStudentRecordById(String id);

    /**
     * 根据ID查询学籍
     *
     * @param ids 学籍ID
     * @return 学籍
     */
    List<StudentRecord> getByIds(Collection<String> ids);

    /**
     * 查询学籍对应的订单
     *
     * @param studentRecordId 学籍ID
     * @return 订单ID 没有关联的订单返回null(如：同学科转班没有订单)
     */
    String findOrderId(String studentRecordId);

    /**
     * 根据订单ID查询对应的学籍
     *
     * @param orderId 订单ID
     * @return 学籍
     */
    StudentRecord findStudentRecord(String orderId);

    /**
     * 学籍结算
     *
     * @param studentRecordId 学籍ID
     * @param settlementDate  结算日期
     * @param calculator      结算计算器
     * @return 结算结果
     */
    SettlementResult studentRecordSettlement(String studentRecordId,
                                             final LocalDate settlementDate,
                                             SettlementCalculator calculator);

    /**
     * 学籍有一次支付
     *
     * @param studentRecordId 学籍ID
     * @param amount          支付金额
     * @return 是否支付完成
     */
    boolean paid(String studentRecordId, int amount);

    /**
     * 学籍有退费
     *
     * @param studentRecordId 学籍ID
     * @param amount          支付金额
     */
    void refund(String studentRecordId, int amount );

    /**
     * 学籍退费，会根据退费金额调整"应收明细"及"实际应收金额"
     *
     * @param refundDTO 退费参数
     * @param isCheckAmount 是否校验退费金额
     */
    void refund(StudentRecordRefundDTO refundDTO ,boolean isCheckAmount);

    /**
     * 锁定学籍
     *
     * @param studentRecordIds 学籍ID
     * @param referenceType 凭单类型
     * @param referenceId 凭单ID
     * @throws BizException 有学籍锁定失败时抛出
     */
    void locks(Set<String> studentRecordIds ,ReferenceTypeEnum referenceType , String referenceId);

    /**
     * 解锁学籍
     *
     * @param studentRecordIds 学籍ID
     * @param referenceType 凭单类型
     * @param referenceId 凭单ID
     * @throws BizException 有学籍解锁失败时抛出
     */
    void unlocks(Set<String> studentRecordIds,ReferenceTypeEnum referenceType , String referenceId);

    /**
     * 解锁单个学籍
     *
     * @param studentRecordId 学籍ID
     */
    void unlock(String studentRecordId);

    /**
     * 修改学籍的调整金额
     *
     * @param studentRecordId  学籍ID
     * @param adjustmentAmount 调整金额(单位:分)
     * @author 高昌露
     * @since 2023/11/23 17:11
     */
    void updateAdjustmentAmount(@NonNull String studentRecordId, @NonNull Integer adjustmentAmount);

    /**
     * 根据学籍ID查询校区ID
     *
     * @param recordDO
     * @return
     */
    List<String> findSchoolIdsByRecordId(@NonNull StudentRecordDO recordDO);

    /**
     * 功能描述: 学员信息查询-学籍信息列表（包含：支付信息、发票信息）
     *
     * @param studentId 学员id
     * @author 陈早庆
     * @update:[变更日期2023年11月30日][更改人姓名][变更描述]
     * @since 2023年11月30日
     */
    List<StudentRecordInfoDO> listStudentRecordInfo(Integer studentId);
    List<StudentRecordInfoDO> listStudentRecordInfoByStudentRecordId(Integer studentId, String studentRecordId);

    /**
     * <p>
     * 根据学生ID查询关联的班级
     * </p>
     *
     * @param studentId      学生ID
     * @param delayFlag
     * @param suspensionFlag
     * @param upgradeable  是否升级就业班
     * @return 关联的班级列表
     * @author zhouwei
     * @since 2023/12/14 3:25 PM
     **/
    List<StudentRecordClazzDTO> findClazzByStudentId(Integer studentId, Boolean delayFlag, Boolean suspensionFlag,Boolean upgradeable) ;

    /**
     * <p>
     * 查询班级在途学籍列表
     * </p>
     *
     * @param clazzId 班级ID
     * @param ids  学籍ID
     * @return 在途学籍列表， 没有数据返回 null
     * @author zhouwei
     * @since 2024/1/12 9:52 AM
     **/
    List<ClazzLockRecordDO> findClazzLockRecordListByClazzId( Integer clazzId, List<String> ids);

    List findNotInClazzRecord(Integer clazzId ,List<String> studentRecordIds) ;

    List<StudentRecordInfoDO> listStudentRecordInfo(Integer studentId, Integer clazzId, String studentRecordId);
    List<StudentRecordInfoDO> listStudentRecordInfoByjournalRefundId(String studentRecordId, Integer clazzId);

    /**
     * 查询实际在班人数
     *
     * @return int
     */
    int findInClazzCount(Integer clazzId);

    Page<SpecialClazz> findSpecialClazzPage(BasePageRequest<SpecialClazzQuery> query);

    SpecialClazz findSpecialClazzById(Integer clazzId);

    /**
     * 功能描述:
     * <p>
     * 退费班级信息
     *
     * @param studentRecordId 学籍id
     * @author 陈早庆
     * @update:[变更日期2023年12月08日][更改人姓名][变更描述]
     * @since 2023年12月08日
     */
    List<RefundClazzInfosDO> listRefundClazzInfos(String studentRecordId);


    List<StudentRecordJournalVo> journals(Integer studentId, String studentRecordId);

    /**
     * 费用转移：修改学籍 e2_student_record “转出金额 transfer_out_amount”
     * @param studentRecordId 学籍ID
     * @param transferAmount 费用转移转出金额
     */
    void updateTransferOutAmount(String studentRecordId, Integer transferAmount);
    // 费用转移：修改学籍 e2_student_record "转入金额 transfer_from_amount"
    // // 待生效的学籍，在有金额转入后，变为已生效学籍
    void updateTransferFromAmount(String studentRecordId, Integer transferAmount);

    void syncSjc(Collection<String> recordIdCollection);
}
